package client;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;
import java.util.Properties;

import security.keyManagement.KeyStoreManager;
import utils.PropertiesUtils;
import client.exceptions.SocketUninitializedException;
import connection.TCPSecureClientSocket;
import connection.TCPSecureSocket.EstablishmentModes;
import connection.exception.ConnectionResetException;

/**
 * Singleton class, containing communication methods,
 * accessible by the whole Application.
 * 
 * @author raVemjr
 *
 */
public class ClientData {

	private static ClientData _clientDataSingleton;

	private TCPSecureClientSocket _secureSocket;
	
	private KeyStoreManager _keyStoreManager;
	
	public ClientData(){
		try {
			_keyStoreManager = new KeyStoreManager(null, false, false);
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		_clientDataSingleton = this;
	}

	/**
	 * Returns the instance of the {@link ClientData}
	 * object.
	 * 
	 * @return
	 */
	public static ClientData getInstance() {
		return _clientDataSingleton;
	}
	
	public KeyStoreManager getKeyStoreManager(){
		return _keyStoreManager;
	}

	/**
	 * Initializes the Secure Socket, using the Citizen's Card
	 * authentication method.
	 * @param name 
	 * @throws UnknownHostException 
	 */
	public boolean initWithCCAuth(String name) throws UnknownHostException {
		InetSocketAddress certcopAddress = getCertcopAddress();

		if(certcopAddress.isUnresolved())
			throw new UnknownHostException();
		
		try {
			_secureSocket = new TCPSecureClientSocket(certcopAddress, EstablishmentModes.CitizenCard, name, null);
		} catch (ConnectionResetException e) {
			e.printStackTrace();
		}
		
		return _secureSocket.isSecureChannelEstablished();
	}

	/**
	 * Initializes the Secure Socket, using a username-password
	 * authentication method.
	 * 
	 * @param username The provided username.
	 * @param password The provided password.
	 * @throws UnknownHostException 
	 */
	public boolean initWithUserPassAuth(String username, String password) throws UnknownHostException {    	
		InetSocketAddress certcopAddress = getCertcopAddress();

		if(certcopAddress.isUnresolved())
			throw new UnknownHostException();
		
		try {
			_secureSocket = new TCPSecureClientSocket(certcopAddress, EstablishmentModes.UsernamePassword, username, password);
		} catch (ConnectionResetException e) {
			e.printStackTrace();
		}
		
		return _secureSocket.isSecureChannelEstablished();
	}

	/**
	 * Initializes the Secure Socket, without using any authentication
	 * method.
	 * @throws UnknownHostException 
	 */
	public void initWithoutAuth() throws UnknownHostException {
		InetSocketAddress certcopAddress = getCertcopAddress();

		if(certcopAddress.isUnresolved())
			throw new UnknownHostException();

		_secureSocket = new TCPSecureClientSocket(certcopAddress);
	}

	/**
	 * Uses the local socket to send an object.
	 * 
	 * @param obj The object to send
	 * @throws SocketUninitializedException 
	 * @throws ConnectionResetException 
	 */
	public void send(Object obj) throws SocketUninitializedException, ConnectionResetException {
		if(_secureSocket == null)
			throw new SocketUninitializedException();

		_secureSocket.send(obj);
	}

	/**
	 * Uses the local socket to receive an object.
	 * 
	 * @return The object received.
	 * @throws SocketUninitializedException 
	 * @throws ConnectionResetException
	 */
	public Object receive() throws ConnectionResetException, SocketUninitializedException {
		if(_secureSocket == null)
			throw new SocketUninitializedException();

		return _secureSocket.receive();
	}

	private InetSocketAddress getCertcopAddress(){
		Properties clientProperties = PropertiesUtils.getPropertiesFromFile("config/CERTCOPClient.properties");

		String ip = clientProperties.getProperty("certcopIp");
		int port = Integer.parseInt(clientProperties.getProperty("certcopPort"));

		return new InetSocketAddress(ip, port);
	}
}
